require 'getoptlong'
require 'date'
require 'date/format'

# -----------------(*)-----------------(*)-----------------(*)-----------------
#  Subversion
#     svn import "<LocalDir/>"  "<URL/>"  --username mnemotronic@gmail.com --password

#     svn checkout "<URL/>" "<LocalDir/>" 
#     svn resolve --accept working logs "<LocalDir/Filename>"
#     svn revert "<LocalDir/Filename>"
#     svn checkout "<URL/>" "<LocalDir/>" 

#     svn propset svn:keywords "Author Date URL Id Revision Header"  "<LocalDir/>\<FileName>"
#     svn propset Originator "paul_m_thompson@yahoo.com"             "<LocalDir/>\<FileName>"
#     svn propset Script <ScriptName"                                "<LocalDir/>\<FileName>"
#     svn commit .
#     svn checkout "<URL/>" "<LocalDir/>" 

#     "C:/Users/pthompson/Documents/Source/rb/SLM_Debug_Log_Analysis/SLM_LARLO.rb"
#     "%SRC%/rb/SLM_Debug_Log_Analysis/SLM_LARLO.rb"
#     "https://serena-teamtrack-mashups.googlecode.com/svn/trunk/SLM_Debug_Log_Analysis/src/"

# -----------------(*)-----------------(*)-----------------(*)-----------------

#  File:       C:\Users\pthompson\Documents\Source\rb\SLM_LARLO.rb
#              Serena License Manager Log Analysis and Ruby Learning Opportunity
#
#  $URL: http://serena-teamtrack-mashups.googlecode.com/svn/trunk/SLM_Debug_Log_Analysis/src/SLM_LARLO.rb $
#  $Script: Serena License Manager Log Analysis and Ruby Learning Opportunity $
#  $Creator: paul_m_thompson@yahoo.com $
#  $Revision: 89 $
#  $Date: 2013-09-07 06:55:57 +0000 (Sat, 07 Sep 2013) $
#  $Author: mnemotronic@gmail.com $

# -----------------{*}-----------------{*}-----------------{*}-----------------

class UserInOutLine
   include Comparable
   attr_accessor(:inout , :inOutDateTime , :inDateTime , :outDateTime , :userId , :hostId)
   
   OUT=0
   IN=1
   DENIED=2
   UNSUPPORTED=3
   
   # Primary sort key is user loginID.  Secondary is In or Out time.  Tertiary is In/Out flag.
   def <=>(other)
      name_match = @userId <=> other.userId
      datetime_match = @inOutDateTime <=> other.inOutDateTime
      
      (name_match==0) ? (datetime_match==0 ? (@inout <=> other.inout) : datetime_match) : name_match
   end
   
   def initialize(io,iodt,uid,hid)
      # Defaults
      @inout = io
      @inOutDateTime = iodt
      if iodt==OUT then outDateTime = iodt else inDateTime = iodt end
      @userId = uid
      @hostId = hid
      # args.each { |key,val| puts "UserInOutLine.initialize :: key,val=#{key},#{val}" }
   end
   
   def to_s()
      case @inout
         when OUT then str_ret = 'inout:Out'
         when IN then str_ret = 'inout:In'
         else str_ret = "<unk #{@inout}>"
      end
      
      str_ret =  ',' + @inOutDateTime.to_s + \
                  ',' + @inDateTime.to_s + \
                  ',' + @outDateTime.to_s + \
                  ',' + @userId.to_s + \
                  ',' + @hostId.to_s
                  
      return str_ret
   end
   alias to_str to_s
end

# -----------------{*}-----------------{*}-----------------{*}-----------------
# Print help and GTFO
def showhelp
   puts <<-EOF
      ruby "#{$0}" [options] [file(s)]
      Where file(s) are one or more files.  Wildcards are expanded.
       options are 

      -h, -? --help:
      show help

   EOF
   exit(0)
end
# -----------------{*}-----------------{*}-----------------{*}-----------------

#  CONSTANT          =  "First letter must be Uppercase.  Generally ALL UPPERCASE"
#  local_var         =  "First letter is lower case or UNDERSCORE".
#  _local_var        =  "First letter is lower case or UNDERSCORE".
#  @instance_var     =  "First letter must be AT"
#  @@class_var       =  "Must start with 2 AT signs"
#  $global
#  :symbol              "Everything has a symbol.  Symbols are unique".  Symbol.all_symbols --> array

# -----------------[*]-----------------[*]-----------------[*]-----------------
cmdLineOpts = GetoptLong.new(
   [ '--help'                 , '-h','-?'    , GetoptLong::OPTIONAL_ARGUMENT ] 
)
# -----------------[*]-----------------[*]-----------------[*]-----------------


cmdLineOpts.each do |opt, arg|
   case opt
      when '--help'
         showhelp
   end
end

# All f
puts "argv=#{ARGV}"

#  $/    Input record seperator
#  $\    Output record seperator
#  $,    Input field seperator
#  $;    Seperator for String#split
#  $.    Current input line number
#  $<    Concatenation of all files on cmd line.  Same as ARGF

# --------------------
# --------------------


#  C:\Users\pthompson\Documents\Serena\Consulting Services Work\_Services On Demand\Brocade\Licenses\licenseusage_log_06172013.log
#  C:\Users\pthompson\Documents\Serena\Consulting Services Work\_Services On Demand\Brocade\Licenses\SerenaLicenseServer.201304291933-201306162246.log
#  C:\Users\pthompson\Documents\Serena\Consulting Services Work\_Services On Demand\Brocade\Licenses\SerenaLicenseServer.201306162248-201306172251.log
#  C:\Users\pthompson\Documents\Serena\Consulting Services Work\_Services On Demand\Brocade\Licenses\SerenaLicenseServer.201306192120-201308112242.log
#  C:\Users\pthompson\Documents\Serena\Consulting Services Work\_Services On Demand\Brocade\Licenses\SerenaLicenseServer.201308172236-201309021942.log
#  C:\Users\pthompson\Documents\Serena\Consulting Services Work\_Services On Demand\Brocade\Licenses\users.lst

# There must be at least one server identifier line per SLM debug log file.
# Capture the time-of-day ($1), version info ($2), the server name ($3) and the start date ($4)
SLM_SERVER_STARTDATE_LINE_REGEX = '\s*([\d:]+)\s*\(lmgrd\) FLEXnet Licensing \(([^)]+)\) started on ([\S]+).*\(([^)]+)\)'

# Capture the time-of-day ($1) and the date ($2)
SLM_SERVER_TIMESTAMP_LINE_REGEX = '\s*([\d:]+)\s*\(lmgrd\) TIMESTAMP\s*(.+)\s*$'

# Capture time-of-day ($1), IN or OUT action ($2), feature ($3), user_loginid ($4), host ($5)
SLM_SERVER_USER_INOUT_LINE_REGEX = '\s*([\S]+) \(merant\) (IN|OUT): "(\w+)" ([^@]+)@(\S+)'

# Capture time-of-day ($1), DENIED action ($2), feature ($3), user_loginid ($4), host ($5)
SLM_SERVER_USER_DENIED_ALL_NAMED_IN_USE_LINE_REGEX = '\s*([\S]+) \(merant\) (DENIED): "(\w+)" ([^@]+)@(\S+).*All named licenses are in use'
SLM_SERVER_USER_DENIED_LICENSE_LIMIT_LINE_REGEX = '\s*([\S]+) \(merant\) (DENIED): "(\w+)" ([^@]+)@(\S+).*Licensed number of users already reached'

# Create and pre-compile the Regular expressions for the different lines.
regex_slm_server_startdate_line = /#{SLM_SERVER_STARTDATE_LINE_REGEX}/
regex_slm_server_timestamp_line = /#{SLM_SERVER_TIMESTAMP_LINE_REGEX}/
regex_slm_server_user_inout_line = /#{SLM_SERVER_USER_INOUT_LINE_REGEX}/


#  22:48:20 (lmgrd) FLEXnet Licensing (v10.8.2.1 build 30104) started on hq1wp-sbm01 (IBM PC) (6/16/2013)
#   6:51:47 (lmgrd) TIMESTAMP 6/17/2013

#  22:48:20 (merant) FLEXnet Licensing version v10.8.2.1 build 30104

#  22:48:20 (merant) EXPIRED: TeamTrack
#  22:48:20 (merant) Server started on hq1wp-sbm01 for:	TeamTrackExternal 
#  22:48:20 (merant) TeamTrack	TeamTrack_named TeamTrackTTS_named 
#  22:48:20 (merant) TeamTrackCMZ_named TeamTrackCMN_named TeamTrackTTX_named 
#  22:48:20 (merant) TeamTrackTVC_named TeamTrackTVB_named TeamTrackTTB_named 
#  22:48:20 (merant) TeamTrackTPB_named TeamTrackAPI_named TeamTrackTTT_named 
#  22:48:20 (merant) TeamTrackTSV	
#  22:48:20 (lmgrd) merant using TCP-port 2603
#  22:48:32 (merant) TCP_NODELAY NOT enabled


# Ignore - were going to suggest who should get the named licenses .....
#  22:48:32 (merant) DENIED: "TeamTrack_named" JNG@hq1-up-swe-03  (All named licenses are in use.)
#  22:48:54 (merant) DENIED: "TeamTrack_named" BPERIYA@blr-l7rr78r1  (All named licenses are in use.)
#  23:06:44 (merant) DENIED: "TeamTrack_named" GNAIK@brm-isa-3  (All named licenses are in use.)

# badness.  Count how often this happens
#  23:06:44 (merant) DENIED: "TeamTrack" GNAIK@brm-isa-3  (Licensed number of users already reached. (-4,342))

# huh!?!?
#  23:06:44 (merant) UNSUPPORTED: "TeamTrack" (00D7 4546 2EBA AE42 ) GNAIK@brm-isa-3  (License server system does not support this feature. (-18,327))


# OUT: keep track of:
#     the user
#     the license feature
#     date & time
#     hostname

#  22:48:32 (merant) OUT: "TeamTrack" JNG@hq1-up-swe-03  
#  22:48:54 (merant) OUT: "TeamTrack" BPERIYA@blr-l7rr78r1  


#  23:06:47 (merant) IN: "TeamTrack" VRAVIND@hcl-47813sdb3  
#  23:06:47 (merant) IN: "TeamTrack" JEBENEZE@hcl-lp078  
#  23:06:47 (merant) IN: "TeamTrack" GKUNJUVA@glisa  
#  23:06:47 (merant) IN: "TeamTrack" KNATARA@hcl-82000amb2  

#   6:51:47 (lmgrd) TIMESTAMP 6/17/2013

 
total_bytes = 0
total_lines = 0

server_startup_linecount = 0
timestamp_linecount = 0
user_inout_linecount = 0
denied_all_named_in_use_linecount = 0
denied_license_limit_linecount = 0
unsupported_feature_linecount = 0



current_date = ''
user_inout = Array.new(0,UserInOutLine)
user_sessions = {}



# #############################################################################################
dt = Date._parse('06/17/2013 22:48:54')
puts "dt.inspect=" + dt.inspect
dt = DateTime._parse('06/17/2013 22:48:54')
puts "dt.inspect=" + dt.inspect


newx = UserInOutLine.new(UserInOutLine::IN , 123 ,  'pthompson' , 'somehost')
user_inout.push(newx)
puts "user_inout length=#{user_inout.length}"
puts "user_inout[0]=" + user_inout[0].to_s

puts "\n\n\nExiting...\n"
Kernel.exit
# #############################################################################################


 while line = ARGF.gets
 
   total_lines += 1
   total_bytes += line.chomp!.length
   
   # Server startup line
   if line =~ regex_slm_server_startdate_line 
      server_startup_linecount += 1
      puts "\nServer startup line\nfound SLM Startdate line: " + line 
      puts "time-of-day: " + Regexp.last_match(1) + " // #{$1}"
      puts "version info: " + Regexp.last_match(2) + " // #{$2}"
      puts "server: " + Regexp.last_match(3) + " // #{$3}"
      puts "start date: " + Regexp.last_match(4) + " // #{$4}"
      current_date = $4
   end
   
   # Server TIMESTAMP line
   if line =~ regex_slm_server_timestamp_line 
      timestamp_linecount += 1
      puts "\nTIMESTAMP line\nfound Timestamp line: " + line 
      puts "Time-of-day: #{$1}"
      puts "Timestamp date: #{$2}"
      current_date = $2
   end


   # User action : IN / OUT 
   if line =~ regex_slm_server_user_inout_line
      user_inout_linecount += 1
      puts "\nUser Action line\ntime-of-day: #{$1}"
      puts "action: #{$2}"
      puts "feature: #{$3}"
      puts "user: #{$4}"
      puts "host: #{$5}"
      
    # user_inout[] :: :inout ::= (OUT | IN | DENIED | UNSUPPORTED) , :inOutDateTime , :inDateTime , :outDateTime , :userId , :hostId


     case $2
         when 'IN' 
            newx = UserInOutLine.new(UserInOutLine::IN , DateTime._parse('#{current_date} #$1') , $4 , $5)
            user_inout.push(newx)
         when 'OUT' 
            newx = UserInOutLine.new(UserInOutLine::OUT , DateTime._parse('#{current_date} #$1') , $4 , $5)
            user_inout.push(newx)
         else 
            puts "Unknown action : #{$2}"
      end
   end

 end
 
 puts "\n\n\nfound #{total_lines} lines, #{total_bytes} bytes."
 puts "#{server_startup_linecount} Server startup lines"
 puts "#{timestamp_linecount} TIMESTAMP lines"
 puts "#{user_inout_linecount} IN/OUT lines"
 
 